#pragma once
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<unordered_map>
#include<mutex>
#include"util.hpp"
#include"log.hpp"

const std::string root_path="./data/output/raw.txt"; 

//正排结构体
struct DocInfo
{
    std::string title; 
    std::string content;
    std::string url;
    int doc_id;
};

//倒排结构体
struct InvertElem
{
    std::string word;
    int weight;
    int doc_id;

};

//统计分词次数
struct word_cnt
{
    int title_cnt;
    int content_cnt;
};

//倒排拉链
typedef std::vector<InvertElem> InvertedList;

class Index
{
private:
    // 正排索引
    std::vector<DocInfo> Forward_Index;
    // 倒排索引
    std::unordered_map<std::string, InvertedList> Invert_Index;
    static Index* instance;
    static std::mutex mtx;
private:
    Index()
    {}
    Index(const Index& )=delete;
    Index& operator=(const Index&)=delete;
public:
    ~Index()
    {}
    //获取对象
    static Index* GetInstance()
    {
        if(nullptr==instance)
        {
            mtx.lock();
            if(nullptr==instance)
            {
                instance=new Index();
            }
            mtx.unlock();
        }
        return instance;
    }
    //获取正排索引
    DocInfo* Get_Forward_Index(int doc_id)
    {
        if(doc_id>=Forward_Index.size())
        {
            return nullptr;
        }
        return &Forward_Index[doc_id];
    }
    //获取倒排索引
    InvertedList* Get_Invert_Index(const std::string& word)
    {
        if(Invert_Index.find(word)==Invert_Index.end())
        {
            return nullptr;
        }
        return &Invert_Index[word];
    }

    // 建立索引
    void Build_Index()
    {
        //遍历每一行的内容，根据line建立正排索引
        std::ifstream in(root_path,std::ios::in);
        std::string line;
        int count=0;
        while(std::getline(in,line))
        {
            //std::cout<<"line:" <<line<<std::endl;
            count++;
            if (count % 50 == 0)
            {
                //std::cout << "正排索引建立中：" << count << std::endl;
                LOG(NORMAL,"正排索引建立中: "+std::to_string(count));
            }
            if(nullptr==Build_ForwardIndex(line))
            {
                //std::cout<<"count: "<<count<<std::endl;
                //std::cerr<<"建立正排失败"<<std::endl;
                LOG(WARNING,"count: "+std::to_string(count)+"建立正排失败");
                continue;
            }
        }
        LOG(NORMAL,"正排索引建立成功");
        in.close();
        //std::cout<<Forward_Index.size()<<std::endl;
        //根据正排索引的建立结果，建立倒排索引
        count=0;
        for(auto& item:Forward_Index)
        {
            count++;
            if(count%50==0)
            {
                LOG(NORMAL,"倒排索引建立中: "+std::to_string(count));
            }
            if(!Build_InvertedIndex(item))
            {
                LOG(WARNING,"count: "+std::to_string(count)+"建立倒排失败");
                continue;
            }
        }
        LOG(NORMAL,"倒排索引建立成功");
        LOG(NORMAL,"服务器启动成功");

    }
private:
    DocInfo* Build_ForwardIndex(const std::string& line)
    {
        //将line中的内容分割
        std::vector<std::string> intent;
        const std::string sep="\3";
        util::StringUtil::SplitString(&intent,line,sep);
        if(intent.size()!=3)
        return nullptr;
        //写入vector中
        struct DocInfo doc;
        doc.doc_id=Forward_Index.size();
        doc.title=intent[0];
        doc.content=intent[1];
        doc.url=intent[2];
        Forward_Index.push_back(std::move(doc));

        return &Forward_Index.back();
    }
    //建立倒排
    bool Build_InvertedIndex(const struct DocInfo& doc)
    {
        //将标题进行分词
        std::string title=doc.title;
        std::vector<std::string> title_words;
        util::JiebaUtil::CutString(title,&title_words);
        //将内容进行分词
        std::string content=doc.content;
        std::vector<std::string> content_words;
        util::JiebaUtil::CutString(content,&content_words);
        //根据分词统计分词在标题和内容的次数
        std::unordered_map<std::string,word_cnt> words_cnt;
        for(auto& tword:title_words)
        {
            boost::to_lower(tword);
            words_cnt[tword].title_cnt++;
        }
        for(auto& cword:content_words)
        {
            boost::to_lower(cword);
            words_cnt[cword].content_cnt++;
        }
        //遍历word和次数的unordered_map,建立倒排索引
        for(auto& elem:words_cnt)
        {
            InvertElem ielm;
            ielm.doc_id=doc.doc_id;
            ielm.word=elem.first;
            ielm.weight=elem.second.content_cnt+elem.second.title_cnt*10;
            Invert_Index[elem.first].push_back(ielm);
        }
        return true;
    }
};

Index* Index::instance=nullptr;
std::mutex Index::mtx;




